#Search for a threading library
find_package(Threads)

message(STATUS "Using install prefix: ${CMAKE_INSTALL_PREFIX}")

#Define two directory properties for pushing information up from child directories
define_property(DIRECTORY PROPERTY DIR_SRCS BRIEF_DOCS "Directory source files" FULL_DOCS "Source files within the directory")
define_property(DIRECTORY PROPERTY DIR_TEST_SRCS BRIEF_DOCS "Directory test source files" FULL_DOCS "Test case source files within the directory")

#Determine if we are on OS X, 64-bit Linux, or 32-bit Linux
if(APPLE)
  set(PLATFORM_STR "osx")
else()
  if(CMAKE_SIZEOF_VOID_P EQUAL 8)
    set(PLATFORM_STR "linux64")
  else()
    set(PLATFORM_STR "linux32")
  endif()
endif()

#Should we search for GMP?
if(FIND_GMP)
  #Search for the GNU Multiple Precision Arithmetic Library (GMP)
  find_package(GMP)
  if(NOT GMP_FOUND)
    message(FATAL_ERROR "GMP not found, it is required for building ISL, CLooG, and IEGen")
  endif()
  string(REGEX REPLACE "/include$" "" GMP_PREFIX ${GMP_INCLUDE_DIR})
else()
  #If a prefix for GMP wasn't specified, define it to be the directory of the
  # precompiled binary for GMP
  if(GMP_PREFIX)
    set(GMP_PREFIX_GIVEN "yes")
  else()
    set(GMP_PREFIX_GIVEN "no")
    set(GMP_PREFIX "${PROJECT_SOURCE_DIR}/libs/gmp/${PLATFORM_STR}")
  endif()
endif()

#If the ISL prefix was not given, define it to be the directory of the
# precompiled binary for ISL
if(ISL_PREFIX)
  set(ISL_PREFIX_GIVEN "yes")
else()
  set(ISL_PREFIX_GIVEN "no")
  set(ISL_PREFIX "${PROJECT_SOURCE_DIR}/libs/isl/${PLATFORM_STR}")
endif()

#If the CLooG prefix was not given, define it to be the directory of the
# precompiled binary for CLooG
if(CLOOG_PREFIX)
  set(CLOOG_PREFIX_GIVEN "yes")
else()
  set(CLOOG_PREFIX_GIVEN "no")
  set(CLOOG_PREFIX "${PROJECT_SOURCE_DIR}/libs/cloog/${PLATFORM_STR}")
endif()

#Output the status messages of how the build will be performed
message(STATUS "Using GMP prefix: ${GMP_PREFIX}")
message(STATUS "Using ISL prefix: ${ISL_PREFIX}")
if(BUILD_IEGEN)
  message(STATUS "Using CLooG prefix: ${CLOOG_PREFIX}")
endif()

set(GEN_PARSER_YESNO "No")
if(GEN_PARSER)
  set(GEN_PARSER_YESNO "Yes")
endif()
message(STATUS "Generating parser code: ${GEN_PARSER_YESNO}")

set(BUILD_IEGEN_YESNO "No")
if(BUILD_IEGEN)
  set(BUILD_IEGEN_YESNO "Yes")
endif()
message(STATUS "Building IEGen code: ${BUILD_IEGEN_YESNO}")

set(BUILD_PYTHON_YESNO "No")
if(BUILD_PYTHON)
  set(BUILD_PYTHON_YESNO "Yes")
endif()
message(STATUS "Building Python bindings: ${BUILD_PYTHON_YESNO}")

#Add the necessary include directories for building
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/libs/gtest/include)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/libs/glog)
include_directories(${Threads_INCLUDE_DIR})
include_directories(${GMP_PREFIX}/include)
include_directories(${ISL_PREFIX}/include)
if(BUILD_IEGEN)
  include_directories(${CLOOG_PREFIX}/include)
endif()

#Add the necessary link directories for building
link_directories(${GMP_PREFIX}/lib)
link_directories(${ISL_PREFIX}/lib)
if(BUILD_IEGEN)
  link_directories(${CLOOG_PREFIX}/lib)
endif()

add_definitions(-g -fPIC -Wformat=0)

#The following only matter when building shared libraries
## skip the full RPATH for the build tree
#SET(CMAKE_SKIP_BUILD_RPATH TRUE)
#
## when building, use the install RPATH already
## (so it doesn't need to relink when installing)
#SET(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)
#
## the RPATH to be used when installing
#SET(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib")
#
## don't add the automatically determined parts of the RPATH
## which point to directories outside the build tree to the install RPATH
#SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH FALSE)
#
##Define the equivalent of rpath for libraries on OS X
#SET(CMAKE_INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/lib")

#Process subdirectories
add_subdirectory(iegenlib)
add_subdirectory(iegen)
add_subdirectory(bindings)
add_subdirectory(libs)

#Get the lists of sources
get_property(IEGENLIB_SRCS DIRECTORY iegenlib PROPERTY DIR_SRCS)
get_property(IEGENLIB_TEST_SRCS DIRECTORY iegenlib PROPERTY DIR_TEST_SRCS)
get_property(IEGEN_SRCS DIRECTORY iegen PROPERTY DIR_SRCS)
get_property(IEGEN_TEST_SRCS DIRECTORY iegen PROPERTY DIR_TEST_SRCS)

#Build the iegenlib library
add_library(iegenlib STATIC ${IEGENLIB_SRCS})
add_dependencies(iegenlib isl-proj)
target_link_libraries(iegenlib isl gmp)

#Only generate the parser code if requested to
if(${GEN_PARSER})
  #Find the flex and bison tools
  find_package(FLEX)
  find_package(BISON)

  if(${FLEX_VERSION} LESS 2.5)
    message(FATAL_ERROR "Flex version too low: ${FLEX_VERSION}")
  else()
    message(STATUS "Flex version ok: ${FLEX_VERSION}")
  endif()

  if(${BISON_VERSION} LESS 2.4)
    message(FATAL_ERROR "Bison version too low: ${BISON_VERSION}")
  else()
    message(STATUS "Bison version ok: ${BISON_VERSION}")
  endif()

  if(${FLEX_FOUND} AND ${BISON_FOUND})
    #Generate gen_pres_scanner.cc file
    FLEX_TARGET(gen_pres_scanner iegenlib/parser/pres_parser.l ${CMAKE_CURRENT_BINARY_DIR}/iegenlib/parser/gen_pres_scanner_bin.cc)

    #Generate the gen_pres_parser.cc/gen_pres_parser.hh files
    BISON_TARGET(gen_pres_parser iegenlib/parser/pres_parser.y ${CMAKE_CURRENT_BINARY_DIR}/iegenlib/parser/gen_pres_parser_bin.cc)

    #Setup the proper dependency between the flex and bison files
    ADD_FLEX_BISON_DEPENDENCY(gen_pres_scanner gen_pres_parser)

    #Copy the generated files back to the main source tree if they are 
    #different than the current committed versions
    add_custom_command(TARGET iegenlib
      POST_BUILD
      COMMAND ${CMAKE_COMMAND}
      ARGS -E copy_if_different ${CMAKE_CURRENT_BINARY_DIR}/iegenlib/parser/gen_pres_scanner_bin.cc ${CMAKE_CURRENT_SOURCE_DIR}/iegenlib/parser/gen_pres_scanner.cc
      COMMAND ${CMAKE_COMMAND}
      ARGS -E copy_if_different ${CMAKE_CURRENT_BINARY_DIR}/iegenlib/parser/gen_pres_parser_bin.cc ${CMAKE_CURRENT_SOURCE_DIR}/iegenlib/parser/gen_pres_parser.cc
      COMMAND ${CMAKE_COMMAND}
      ARGS -E copy_if_different ${CMAKE_CURRENT_BINARY_DIR}/iegenlib/parser/gen_pres_parser_bin.hh ${CMAKE_CURRENT_SOURCE_DIR}/iegenlib/parser/gen_pres_parser.hh
      COMMENT "Updating gen_pres_scanner.cc and gen_pres_parser.{cc,hh} in the main source tree")
  endif()
else()
  #Copy the current generated scanner/parser files the build directory
  add_custom_command(
    OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/iegenlib/parser/gen_pres_scanner_bin.cc ${CMAKE_CURRENT_BINARY_DIR}/iegenlib/parser/gen_pres_parser_bin.cc ${CMAKE_CURRENT_BINARY_DIR}/iegenlib/parser/gen_pres_parser_bin.hh
    COMMAND ${CMAKE_COMMAND}
    ARGS -E copy ${CMAKE_CURRENT_SOURCE_DIR}/iegenlib/parser/gen_pres_scanner.cc ${CMAKE_CURRENT_BINARY_DIR}/iegenlib/parser/gen_pres_scanner_bin.cc
    COMMAND ${CMAKE_COMMAND}
    ARGS -E copy ${CMAKE_CURRENT_SOURCE_DIR}/iegenlib/parser/gen_pres_parser.cc ${CMAKE_CURRENT_BINARY_DIR}/iegenlib/parser/gen_pres_parser_bin.cc
    COMMAND ${CMAKE_COMMAND}
    ARGS -E copy ${CMAKE_CURRENT_SOURCE_DIR}/iegenlib/parser/gen_pres_parser.hh ${CMAKE_CURRENT_BINARY_DIR}/iegenlib/parser/gen_pres_parser_bin.hh
    DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/iegenlib/parser/gen_pres_scanner.cc ${CMAKE_CURRENT_SOURCE_DIR}/iegenlib/parser/gen_pres_parser.cc ${CMAKE_CURRENT_SOURCE_DIR}/iegenlib/parser/gen_pres_parser.hh
   COMMENT "Copying gen_pres_scanner.cc and gen_pres_parser.{cc,hh} to the build directory")
endif()

#Compile and link the run_iegenlib_tests executable
add_executable(run_iegenlib_tests run_tests.cc ${IEGENLIB_TEST_SRCS})
target_link_libraries(run_iegenlib_tests iegenlib glog gtest ${CMAKE_THREAD_LIBS_INIT})

#Compile and link the demo_driver executable
add_executable(demo_driver demo_driver.cc)
target_link_libraries(demo_driver iegenlib glog ${CMAKE_THREAD_LIBS_INIT})

#Compile the memory test executable
add_executable(memory_tests memory_tests.cc)
target_link_libraries(memory_tests iegenlib glog ${CMAKE_THREAD_LIBS_INIT})

#Install the iegenlib library and related executable targets
install(TARGETS iegenlib run_iegenlib_tests demo_driver memory_tests
        RUNTIME DESTINATION bin
        ARCHIVE DESTINATION lib)

#Install the iegenlib library headers
install(DIRECTORY iegenlib
        DESTINATION include
        FILES_MATCHING PATTERN "*.h")

#Install the GMP precompiled binaries if they were used for building
if(NOT GMP_PREFIX_GIVEN)
  install(DIRECTORY ${GMP_PREFIX}/lib
                    ${GMP_PREFIX}/include
          DESTINATION ${CMAKE_INSTALL_PREFIX})
endif()

#Install the ISL precompiled binaries if they were used for building
if(NOT ISL_PREFIX_GIVEN)
  install(DIRECTORY ${ISL_PREFIX}/lib
                    ${ISL_PREFIX}/include
          DESTINATION ${CMAKE_INSTALL_PREFIX})
endif()

if(BUILD_IEGEN)
  #Build the iegen library
  add_library(iegen STATIC ${IEGEN_SRCS})
  add_dependencies(iegen cloog-proj)
  target_link_libraries(iegen iegenlib cloog-isl)

  #Compile and link the run_iegen_tests executable
  add_executable(run_iegen_tests run_tests.cc ${IEGEN_TEST_SRCS})
  target_link_libraries(run_iegen_tests iegen glog gtest ${CMAKE_THREAD_LIBS_INIT})

  #Install the iegen library and related executable targets
  install(TARGETS iegen run_iegen_tests
          RUNTIME DESTINATION bin
          ARCHIVE DESTINATION lib)

  #Install the iegen library headers
  install(DIRECTORY iegen
          DESTINATION include
          FILES_MATCHING PATTERN "*.h")

  #Install the CLOOG precompiled binaries if they were used for building
  if(NOT CLOOG_PREFIX_GIVEN)
    install(DIRECTORY ${CLOOG_PREFIX}/lib
                      ${CLOOG_PREFIX}/include
                      ${CLOOG_PREFIX}/bin
            DESTINATION ${CMAKE_INSTALL_PREFIX})
  endif()
endif()
